/*
 * To report bug-fixes or to send in suggestions, you
 * can email me at nish@voidnish.com 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;

namespace MultiColumnComboBoxDemo
{
    public class MultiColumnComboBox : ComboBox
    {
        public MultiColumnComboBox()
        {
            DrawMode = DrawMode.OwnerDrawVariable;            
        }

        const int columnPadding = 5;
        private float[] columnWidths = new float[0];    //-->Mang do dai cai cot
        private String[] columnNames = new String[0];   //-->Mang cai cot
        private int valueMemberColumnIndex = 0;         

        public new DrawMode DrawMode 
        { 
            get
            {
                return base.DrawMode;
            } 
            set
            {
                if (value != DrawMode.OwnerDrawVariable)
                {
                    throw new NotSupportedException("Needs to be DrawMode.OwnerDrawVariable");
                }
                base.DrawMode = value;
            }
        }

        public new ComboBoxStyle DropDownStyle
        { 
            get
            {
                return base.DropDownStyle;
            } 
            set
            {
                if (value == ComboBoxStyle.Simple)
                {
                    throw new NotSupportedException("ComboBoxStyle.Simple not supported");
                }
                base.DropDownStyle = value;
            } 
        }

        protected override void OnDataSourceChanged(EventArgs e)
        {
            base.OnDataSourceChanged(e);
            InitializeColumns();
        }
        // Lay ve cac cot trong Collection
        private void InitializeColumns()
        {
            try
            {
                PropertyDescriptorCollection propertyDescriptorCollection = DataManager.GetItemProperties();

                columnWidths = new float[propertyDescriptorCollection.Count];
                columnNames = new String[propertyDescriptorCollection.Count];

                for (int colIndex = 0; colIndex < propertyDescriptorCollection.Count; colIndex++)
                {
                    columnNames[colIndex] = propertyDescriptorCollection[colIndex].Name;
                }
            }
            catch { }
        }

        protected override void OnValueMemberChanged(EventArgs e)
        {
            base.OnValueMemberChanged(e);

            InitializeValueMemberColumn();
        }
        // Lay ve index column ValueMember
        private void InitializeValueMemberColumn()
        {
            int colIndex = 0;
            foreach (String columnName in columnNames)
            {
                if (String.Compare(columnName, ValueMember, true, CultureInfo.CurrentUICulture) == 0)
                {
                    valueMemberColumnIndex = colIndex;
                    break;
                }
                colIndex++;
            }
        }

        protected override void OnDropDown(EventArgs e)
        {
            base.OnDropDown(e);
            this.DropDownWidth = (int)CalculateTotalWidth();
        }

        protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            base.OnMeasureItem(e);

            if (DesignMode)
                return;

            for (int colIndex = 0; colIndex < columnNames.Length; colIndex++)
            {
                if (colIndex != valueMemberColumnIndex)
                {
                    string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[colIndex]));
                    SizeF sizeF = e.Graphics.MeasureString(item, Font);
                    columnWidths[colIndex] = Math.Max(columnWidths[colIndex], sizeF.Width);
                }
                else
                    columnWidths[colIndex] = 0;
            }

            float totWidth = CalculateTotalWidth();//Tong do dai Item

            e.ItemWidth = (int)totWidth;
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            base.OnDrawItem(e);

            if (DesignMode)
                return;

            e.DrawBackground();

            Rectangle boundsRect = e.Bounds;
            int lastRight = 0;

            using (Pen linePen = new Pen(SystemColors.GrayText))
            {
                using (SolidBrush brush = new SolidBrush(ForeColor))
                {
                    if (columnNames.Length == 0 && e.Index != -1)
                    {
                        e.Graphics.DrawString(Convert.ToString(Items[e.Index]), Font, brush, boundsRect);
                    }
                    else
                    {
                        for (int colIndex = 0; colIndex < columnNames.Length; colIndex++)
                        {
                            if (colIndex != valueMemberColumnIndex)
                            {
                                string item = Convert.ToString(FilterItemOnProperty(Items[e.Index], columnNames[colIndex]));

                                boundsRect.X = lastRight;
                                boundsRect.Width = (int)columnWidths[colIndex] + columnPadding;
                                lastRight = boundsRect.Right;
                                e.Graphics.DrawString(item, Font, brush, boundsRect);
                                if (colIndex < columnNames.Length - 1)
                                {
                                    e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, boundsRect.Right, boundsRect.Bottom);
                                }
                            }
                        }
                    }
                }
            }

            e.DrawFocusRectangle();
        }

        #region Method

        // Tong do dai Item
        private float CalculateTotalWidth()
        {
            float totWidth = 0;
            foreach (int width in columnWidths)
            {
                totWidth += (width + columnPadding);
            }
            return totWidth + SystemInformation.VerticalScrollBarWidth;
        }
        #endregion

        public event EventHandler OnPressEnter;
        public event EventHandler OnPressLeft;
        public event EventHandler OnPressRight;
        public event EventHandler OnPressUp;
        public event EventHandler OnPressDown;
        public event EventHandler OnPressPageDown;
        public event EventHandler OnPressPageUp;
        private Control _PrevText;
        private Control _NextText;
        public Control PrevText
        {
            set
            {
                _PrevText = value;
            }
            get
            {
                return _PrevText;

            }
        }
        public Control NextText
        {
            set
            {
                _NextText = value;
            }
            get
            {
                return _NextText;

            }
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    if (OnPressEnter != null) OnPressEnter(this, e);
                    if (_NextText != null) _NextText.Focus();
                    if (_NextText is Button)
                    {
                        ((Button)_NextText).PerformClick();
                        e.Handled = true;
                    }

                    break;
                case Keys.Left:
                    if (OnPressLeft != null) OnPressLeft(this, e);
                    if (_PrevText != null) _PrevText.Focus();
                    break;
                case Keys.Right:
                    if (OnPressRight != null) OnPressRight(this, e);
                    if (_NextText != null) _NextText.Focus();
                    break;
                case Keys.Up:
                    if (OnPressUp != null) OnPressUp(this, e);
                    break;
                case Keys.Down:
                    if (OnPressDown != null) OnPressDown(this, e);
                    break;
                case Keys.PageDown:
                    if (OnPressPageDown != null) OnPressPageDown(this, e);
                    break;
                case Keys.PageUp:
                    if (OnPressPageUp != null) OnPressPageUp(this, e);
                    break;
            }
        }
    }
}
